package com.icinfo.cloud.provider.punish.common.seal.utils;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.icinfo.cloud.common.core.page.PageResponse;
import com.icinfo.cloud.provider.common.constant.Constant;
import com.icinfo.cloud.provider.common.exception.BusinessException;
import com.icinfo.cloud.provider.common.utils.IrsSignUtil;
import com.icinfo.cloud.provider.common.utils.SpringContextUtil;
import com.icinfo.cloud.provider.punish.common.seal.dto.BindSealPageDto;
import com.icinfo.cloud.provider.punish.common.seal.vo.BindSealVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;

/**
 * 重庆签章工具类
 *
 * @author yunchao.peng
 * @create 2023-06-20 18:53
 */
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "sign")
public class ChongQingSignUtil {

    private static final TimedCache<String, String> timedCache = CacheUtil.newTimedCache(4);
    private static String URL;
    private static String SEALCODE;
    private static String USERNAME;
    private static String PWD;

    public static String getUSERNAME() {
        return USERNAME;
    }

    @Value("${sign.userName}")
    public void setUSERNAME(String USERNAME) {
        ChongQingSignUtil.USERNAME = USERNAME;
    }

    public static String getPWD() {
        return PWD;
    }

    @Value("${sign.pwd}")
    public void setPWD(String PWD) {
        ChongQingSignUtil.PWD = PWD;
    }

    public static String getPath() {
        return URL;
    }

    @Value("${sign.url}")
    public void setPath(String path) {
        ChongQingSignUtil.URL = path;
    }

    public static String getSealCode() {
        return SEALCODE;
    }

    @Value("${sign.sealCode}")
    public void setSealCode(String sealCode) {
        ChongQingSignUtil.SEALCODE = sealCode;
    }

    public static AuthToken getAuthToken() {
//        String token = timedCache.get("token");
//        if (StringUtils.isNotBlank(token)) {
//            System.out.println("缓存token========:"+token);
//            return JSONObject.parseObject(token, AuthToken.class);
//        }
        String url = URL + "/paas-auth/oauth/token";
        HttpRequest post = HttpUtil.createPost(url);
        post.basicAuth(USERNAME, PWD);
        HashMap<String, Object> param = new HashMap<>();
        param.put("grant_type", "aos_client_credentials");
        param.put("scope", "all");
        post.form(param);
        String body = post.execute().body();
        log.info("获取授权接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            AuthToken authToken = response.getObject("data", AuthToken.class);
//            timedCache.put("token", JSONObject.toJSONString(authToken), authToken.getExpiresIn().longValue() * 1000);
//            System.out.println("获取token========:"+JSONObject.toJSONString(authToken));

            return authToken;
        }
        throw new BusinessException("获取授权接口异常异常");
    }

    public static PageResponse<BindSealVo> getBindSealPage(BindSealPageDto dto) {
        HttpRequest post = createAuthPost("/paas-composite-seal/sealBind/query/list");
        JSONObject params = new JSONObject();
        params.put("currentPage", dto.getPageNum());
        params.put("pageSize", dto.getLength());
        if (Objects.nonNull(dto.getCardNo())) {
            params.put("personIdentity", dto.getCardNo());
        }
        if (Objects.nonNull(dto.getUsci())) {
            params.put("socialCreditCode", dto.getUsci());
        }
        post.body(params.toJSONString());
        String resultBody = post.execute().body();
        log.info("get remote bind seal list => {}", resultBody);
        JSONObject result = JSON.parseObject(resultBody);
        if (!Boolean.TRUE.equals(result.getBoolean("success"))) {
            throw new BusinessException("获取签章信息失败：" + Optional.ofNullable(result.getString("message")).orElse(""));
        }
        //获取数据
        List<BindSealVo> voList = result.getJSONArray("data").toJavaList(BindSealVo.class);
        PageResponse<BindSealVo> response = new PageResponse<>();
        Long total = result.getLong("total");
        response.setData(voList);
        response.setRecordsTotal(total);
        response.setRecordsFiltered(total);
        return response;
    }


    /**
     * 上传文件
     *
     * @return
     */
    public static String upload(File file) {
        HttpRequest post = createAuthPost("/paas-standard-sdk/file/upload");
        HashMap<String, Object> param = new HashMap<>();
        param.put("file", file);
        post.form(param);
        String body = post.execute().body();
        log.info("获取文件上传接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            return response.getJSONObject("data").getString("fileId");
        } else {
            //防止因为签章token无效 但处罚缓存中的token 仍然有效
            HttpRequest rePost = createAuthRePost("/paas-standard-sdk/file/upload");
            param.put("file", file);
            post.form(param);
            String rebody = rePost.execute().body();
            log.info("获取文件上传接口详情,{}", rebody);
            JSONObject reResponse = JSONObject.parseObject(rebody);
            if (HttpStatus.HTTP_OK == reResponse.getInteger("code")) {
                return reResponse.getJSONObject("data").getString("fileId");
            }
        }
        throw new BusinessException("上传接口失败");
    }

    private static HttpRequest createAuthPost(String url) {
        AuthToken authToken = getAuthToken();
        url = URL + url;
        HttpRequest post = HttpUtil.createPost(url);
        HashMap<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + authToken.getAccessToken());
        post.addHeaders(header);
        return post;
    }

    /**
     * 创建irs的post请求 签署请求
     *
     * @param url      请求路径
     * @param actionId irs网关id
     * @return
     */
    private static HttpRequest createIrsSealBindSignAuthPost(String url, String actionId, Integer sealCount, Map<String, Object> businessParams) {
        AuthToken authToken = getAuthToken();
        HttpRequest post = HttpUtil.createPost(url);
        HashMap<String, String> header = new HashMap<>();
        String currentTimeStamp = String.valueOf(System.currentTimeMillis());
        //AK/SK
        String appKey = "44a760a78a4a1a9701454059a785955d";
        String appSecret = "97f9d6e8f74dddb36f0362acc31c3a16040c61f1aa8bbacc04909b894b1ab04439559a06f408f1d4d0b6965449a62dbb";
        header.put("Authorization", "Bearer " + authToken.getAccessToken());
        //计算签章数量
        if (Objects.nonNull(sealCount)) {
            header.put("X-SEAL-COUNT", String.valueOf(sealCount));
        }
        header.put("X-Auth-Key", appKey);
        header.put("X-Auth-ActionId", actionId);
        header.put("X-Auth-Timestamp", currentTimeStamp);
        header.put("X-Auth-Signature", irsSign(appSecret, header, businessParams));
        log.info("irs请求头,{}", JSON.toJSONString(header));
        post.addHeaders(header);
        return post;
    }

    /**
     * irs 加签 签名
     * @param header 请求头
     * @param appSecret        appSecret
     * @param businessParam    业务参数
     * @return
     */
    private static String irsSign(String appSecret, Map<String, String> header, Map<String, Object> businessParam) {
        Map<String, Object> sign = new HashMap<>();
        sign.putAll(header);
        //业务参数加签
        sign.putAll(businessParam);
        log.info("irs签名内容=>{}", JSON.toJSONString(sign));
        try {
            return IrsSignUtil.getSign(appSecret, sign);
        } catch (Exception e) {
            throw new BusinessException("irs加签失败");
        }
    }

    /**
     * 计算签章数量
     *
     * @param sealBindSign
     * @return
     */
    private static int calculateSealCount(SealBindSign sealBindSign) {
        if (Objects.isNull(sealBindSign) || CollUtil.isEmpty(sealBindSign.getFileInfo())) {
            return 0;
        }
        //统计签署文件的签章数量
        return sealBindSign.getFileInfo().stream()
                //获取单个文件的签章数
                .map(file -> Objects.isNull(file.getSignInfo()) ? 0 : file.getSignInfo().size())
                //转换BigDecimal
                .map(BigDecimal::valueOf)
                //求和
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .intValue();
    }

    private static HttpRequest createAuthRePost(String url) {
        AuthToken authToken = getAuthReToken();
        url = URL + url;
        HttpRequest post = HttpUtil.createPost(url);
        HashMap<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + authToken.getAccessToken());
        post.addHeaders(header);
        return post;
    }

    public static AuthToken getAuthReToken() {
        String url = URL + "/paas-auth/oauth/token";
        HttpRequest post = HttpUtil.createPost(url);
        post.basicAuth(USERNAME, PWD);
        HashMap<String, Object> param = new HashMap<>();
        param.put("grant_type", "aos_client_credentials");
        param.put("scope", "all");
        post.form(param);
        String body = post.execute().body();
        log.info("获取授权接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            AuthToken authToken = response.getObject("data", AuthToken.class);
            timedCache.put("token", JSONObject.toJSONString(authToken), authToken.getExpiresIn().longValue() * 1000);
            System.out.println("获取token========:" + JSONObject.toJSONString(authToken));
            return authToken;
        }
        throw new BusinessException("获取授权接口异常异常");
    }

    private static HttpRequest createAuthGet(String url) {
        HttpRequest authPost = createAuthPost(url);
        authPost.setMethod(Method.GET);
        return authPost;
    }

    public static List<Position> filePosition(String fileId, String keyWord, List<String> positionType) {
        HttpRequest authPost = createAuthPost("/paas-toolbox/file/filePosition");
        JSONObject requestBody = new JSONObject();
        requestBody.put("fileId", fileId);
        requestBody.put("keyWord", keyWord);
        requestBody.put("positionType", positionType);
        log.info("获取文件关键字位置接口请求参数:{}", requestBody.toJSONString());
        authPost.body(requestBody.toJSONString());
        String body = authPost.execute().body();
        log.info("获取文件关键字位置接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            return response.getJSONObject("data").getJSONArray("positionList").toJavaList(Position.class);
        }
        throw new BusinessException("获取印章位置接口失败");
    }

    public static SealFile sealBindSign(SealBindSign sealBindSign) {
        HttpRequest authPost = createAuthPost("/paas-standard-sdk/sign/sealBindSign");
        String requestBody = JSONObject.toJSONString(sealBindSign);
        log.info("批量签章请求参数,{}", requestBody);
        authPost.body(requestBody);
        String body = authPost.execute().body();
        log.info("获取批量签章结果接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            return response.getObject("data", SealFile.class);
        }
        throw new BusinessException("签署印章异常");
    }

    /**
     * irs对接傲雄 对文件进行签署
     *
     * @param sealBindSign 签章文件签署
     * @return 签署后的文件信息
     */
    public static SealFile irsSealBindSign(SealBindSign sealBindSign) {
        //文件签署api
        String url = "http://23.211.52.151/data_api/dcqc-apiserver/gateway/api/baseOpenUrl/2ea53ab5afe8483e8b69f613eb5558a7";
        String actionId = "00667beca8c64550ac7a74234009d9cc";
        //irs不支持多层级的json，需要把多层级的转换成为一层，例如fileInfo的对象需要转换成json后再给fileInfo赋值
        Map<String, Object> sealBindSignMap = BeanUtil.beanToMap(sealBindSign);
        sealBindSignMap.put("fileInfo", JSONObject.toJSONString(sealBindSign.getFileInfo()));
        //获取请求
        HttpRequest authPost = createIrsSealBindSignAuthPost(url, actionId, calculateSealCount(sealBindSign), sealBindSignMap);
        String requestBody = JSON.toJSONString(sealBindSignMap);
        log.info("批量irs签章请求参数,{}", requestBody);
        authPost.body(requestBody);
        String body = authPost.execute().body();
        log.info("获取irs批量签章结果接口详情,{}", body);
        JSONObject response = JSONObject.parseObject(body);
        if (HttpStatus.HTTP_OK == response.getInteger("code")) {
            JSONObject innerData = response.getJSONObject("data");
            if (HttpStatus.HTTP_OK == innerData.getInteger("code")) {
                return innerData.getObject("data", SealFile.class);
            }
        }
        throw new BusinessException("irs签署印章异常");
    }

    public static byte[] downLoad(String fileId) {
        log.info("下载文件接口,文件id {}", fileId);
        HttpRequest authGet = createAuthGet("/paas-standard-sdk/file/download/" + fileId);
        return authGet.execute().bodyBytes();
    }

    /**
     * 获取签章的文件
     *
     * @return
     */
    public static byte[] getSignFileByte(File file, String sealCode) {
        String fileId = upload(file);
        List<Position> positions = filePosition(fileId, "签章处", Collections.singletonList("SEAL"));
        SealBindSign sealBindSign = new SealBindSign();
        sealBindSign.setThirdBizId("test");
        ArrayList<SealBindSign.FileInfoBean> sealInfoBeans = new ArrayList<>();
        SealBindSign.FileInfoBean fileInfoBean = new SealBindSign.FileInfoBean();
        fileInfoBean.setFileId(fileId);
        SealBindSign.FileInfoBean.SignInfoBean sealInfoBean = new SealBindSign.FileInfoBean.SignInfoBean();
        Position position = positions.get(0);
        sealInfoBean.setPage(position.getPage());
        SealBindSign.FileInfoBean.SignInfoBean.RectangleBean rectangleBean = new SealBindSign.FileInfoBean.SignInfoBean.RectangleBean();
        BeanUtil.copyProperties(position, rectangleBean);
        sealInfoBean.setRectangle(rectangleBean);
        sealInfoBean.setSn(Constant.INTEGER_0);

        SealBindSign.FileInfoBean.SignInfoBean.SealInfoBean sealInfo = new SealBindSign.FileInfoBean.SignInfoBean.SealInfoBean();
        // todo 测试印章.
        sealInfo.setBindCode(sealCode);
        //sealInfo.setBindCode(SEALCODE);
        sealInfoBean.setSealInfo(sealInfo);
        List<SealBindSign.FileInfoBean.SignInfoBean> singInfo = new ArrayList<>();
        singInfo.add(sealInfoBean);
        fileInfoBean.setSignInfo(singInfo);
        sealInfoBeans.add(fileInfoBean);
        sealBindSign.setFileInfo(sealInfoBeans);
        //签署文件 2023/12/21 正式环境需要切换irs签署文件
        SealFile sealFile = SpringContextUtil.checkIsPrdProfile() ? irsSealBindSign(sealBindSign) : sealBindSign(sealBindSign);
        return downLoad(sealFile.getFileList().get(0));
    }

}
